package thread.modoel;

/**
 * @Package javaSE.thread.problem @Author shimmer @Date 2020/5/14 13:26 @TODO 测试：生产者与消费者模型-->利用缓冲区解决：管程法
 */
// 生产者、消费者、产品、缓冲区
public class TestPC {
  public static void main(String[] args) {
    // 创建缓冲区
    SynContainer container = new SynContainer();
    new Producer(container).start();
    new Consumer(container).start();
  }
}

// 生产者
class Producer extends Thread {
  private final SynContainer container;

  public Producer(SynContainer synContainer) {
    this.container = synContainer;
  }

  @Override
  public void run() {
    for (int i = 1; i <= 100; i++) {
      System.out.println("生产了第" + container.content + "只鸡");
      container.push(new Chicken(i));
    }
  }
}

// 消费者
class Consumer extends Thread {
  private final SynContainer container;

  public Consumer(SynContainer synContainer) {
    this.container = synContainer;
  }

  @Override
  public void run() {
    for (int i = 0; i < 100; i++) {
      System.out.println("消费了第" + container.pop().id + "只鸡");
    }
  }
}

// 产品
class Chicken {
  int id;

  public Chicken(int id) {
    this.id = id;
  }
}

// 缓冲区
class SynContainer {
  // 需要一个容器
  Chicken[] chickens = new Chicken[10];
  int content = 1;

  // 生产者生产
  public synchronized void push(Chicken chicken) {
    // 如果容器满了，就等待消费者消费
    if (content >= chickens.length) {
      try {
          System.out.println("队列满，等待有空余空间");
        this.wait();
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
    } 
      // 没满，向容器放入产品
      chickens[content] = chicken;
      content++;
      // 通知消费者消费
      this.notify();
    
  }

  // 消费者消费
  public synchronized Chicken pop() {
    // 如果容器为空，就等待生产者生产
    if (content == 0) {
      try {
        System.out.println("队列为空，等待生产");
        this.wait();
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
    }
    // 不为空，消费产品
    Chicken chicken = chickens[--content];
    // 通知生产者生产
    this.notify();
    return chicken;
  }
}
